// frontend/utils/route-guard.js
/**
 * 路由守卫工具 🛡️
 * 
 * 提供前端路由保护功能，包括权限验证、登录状态检查、路由拦截等
 */

import apiClient from './api-client';

/**
 * 路由守卫类
 */
class RouteGuard {
  /**
   * 初始化路由守卫
   * @param {Object} options - 配置选项
   * @param {Object} options.router - Vue Router实例
   * @param {Object} options.store - Vuex Store实例
   * @param {Array} options.publicRoutes - 公开路由列表
   * @param {String} options.loginRoute - 登录路由
   * @param {String} options.homeRoute - 首页路由
   * @param {Function} options.getToken - 获取令牌函数
   */
  constructor(options = {}) {
    this.options = {
      router: null,
      store: null,
      publicRoutes: ['/login', '/register', '/forgot-password', '/reset-password'],
      loginRoute: '/login',
      homeRoute: '/',
      getToken: () => localStorage.getItem('token'),
      ...options
    };
    
    this.isAuthenticated = false;
    this.userRoles = [];
    this.userPermissions = [];
    
    // 初始化
    if (this.options.router) {
      this.setupGuard();
    }
  }
  
  /**
   * 设置路由守卫
   */
  setupGuard() {
    const { router } = this.options;
    
    router.beforeEach(async (to, from, next) => {
      // 记录路由变化
      console.log(`[路由] ${from.path} -> ${to.path}`);
      
      // 检查是否是公开路由
      if (this.isPublicRoute(to.path)) {
        return next();
      }
      
      // 检查是否已认证
      if (!this.isAuthenticated) {
        const token = this.options.getToken();
        
        if (!token) {
          // 未登录，重定向到登录页
          return next({
            path: this.options.loginRoute,
            query: { redirect: to.fullPath }
          });
        }
        
        try {
          // 验证令牌
          await this.validateToken();
        } catch (error) {
          // 令牌无效，重定向到登录页
          console.error('[路由守卫] 令牌验证失败:', error);
          return next({
            path: this.options.loginRoute,
            query: { redirect: to.fullPath }
          });
        }
      }
      
      // 检查路由权限
      if (to.meta && to.meta.requiresAuth) {
        // 检查角色权限
        if (to.meta.roles && !this.hasRole(to.meta.roles)) {
          console.warn(`[路由守卫] 用户没有所需角色: ${to.meta.roles.join(', ')}`);
          return next({ path: '/403' });
        }
        
        // 检查功能权限
        if (to.meta.permissions && !this.hasPermission(to.meta.permissions)) {
          console.warn(`[路由守卫] 用户没有所需权限: ${to.meta.permissions.join(', ')}`);
          return next({ path: '/403' });
        }
      }
      
      // 通过所有检查，允许访问
      next();
    });
  }
  
  /**
   * 检查是否是公开路由
   * @param {String} path - 路由路径
   * @returns {Boolean} 是否是公开路由
   */
  isPublicRoute(path) {
    return this.options.publicRoutes.some(route => {
      if (typeof route === 'string') {
        return path === route;
      } else if (route instanceof RegExp) {
        return route.test(path);
      }
      return false;
    });
  }
  
  /**
   * 验证令牌
   * @returns {Promise} 验证结果
   */
  async validateToken() {
    try {
      // 调用验证API
      const response = await apiClient.get('/api/v1/auth/validate');
      
      // 更新认证状态
      this.isAuthenticated = true;
      
      // 更新用户信息
      if (response.data && response.data.user) {
        this.userRoles = response.data.user.roles || [];
        this.userPermissions = response.data.user.permissions || [];
        
        // 更新Store
        if (this.options.store) {
          this.options.store.dispatch('auth/setUser', response.data.user);
        }
      }
      
      return response;
    } catch (error) {
      // 清除令牌
      localStorage.removeItem('token');
      this.isAuthenticated = false;
      this.userRoles = [];
      this.userPermissions = [];
      
      // 更新Store
      if (this.options.store) {
        this.options.store.dispatch('auth/logout');
      }
      
      throw error;
    }
  }
  
  /**
   * 检查是否有指定角色
   * @param {Array|String} roles - 所需角色
   * @returns {Boolean} 是否有所需角色
   */
  hasRole(roles) {
    if (!roles || !roles.length) return true;
    
    const requiredRoles = Array.isArray(roles) ? roles : [roles];
    
    return requiredRoles.some(role => this.userRoles.includes(role));
  }
  
  /**
   * 检查是否有指定权限
   * @param {Array|String} permissions - 所需权限
   * @returns {Boolean} 是否有所需权限
   */
  hasPermission(permissions) {
    if (!permissions || !permissions.length) return true;
    
    const requiredPermissions = Array.isArray(permissions) ? permissions : [permissions];
    
    return requiredPermissions.some(permission => this.userPermissions.includes(permission));
  }
  
  /**
   * 登录成功处理
   * @param {Object} userData - 用户数据
   * @param {String} token - 认证令牌
   * @param {String} redirectPath - 重定向路径
   */
  handleLoginSuccess(userData, token, redirectPath) {
    // 保存令牌
    localStorage.setItem('token', token);
    
    // 更新认证状态
    this.isAuthenticated = true;
    this.userRoles = userData.roles || [];
    this.userPermissions = userData.permissions || [];
    
    // 更新Store
    if (this.options.store) {
      this.options.store.dispatch('auth/setUser', userData);
      this.options.store.dispatch('auth/setToken', token);
    }
    
    // 重定向
    if (this.options.router) {
      const path = redirectPath || this.options.homeRoute;
      this.options.router.push(path);
    }
  }
  
  /**
   * 登出处理
   */
  handleLogout() {
    // 清除令牌
    localStorage.removeItem('token');
    
    // 更新认证状态
    this.isAuthenticated = false;
    this.userRoles = [];
    this.userPermissions = [];
    
    // 更新Store
    if (this.options.store) {
      this.options.store.dispatch('auth/logout');
    }
    
    // 重定向到登录页
    if (this.options.router) {
      this.options.router.push(this.options.loginRoute);
    }
  }
}

// 创建默认实例
let routeGuard = null;

/**
 * 初始化路由守卫
 * @param {Object} options - 配置选项
 * @returns {RouteGuard} 路由守卫实例
 */
export function initRouteGuard(options) {
  routeGuard = new RouteGuard(options);
  return routeGuard;
}

/**
 * 获取路由守卫实例
 * @returns {RouteGuard} 路由守卫实例
 */
export function getRouteGuard() {
  if (!routeGuard) {
    console.warn('[路由守卫] 路由守卫未初始化，使用默认配置');
    routeGuard = new RouteGuard();
  }
  return routeGuard;
}

export default {
  RouteGuard,
  initRouteGuard,
  getRouteGuard
};